﻿using Pathfinding;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using UnityEngine;
using UnityEngine.SceneManagement;

[Serializable]
public class Level
{
    [CompilerGenerated]
    private static Action<Level> <>f__am$cache7;
    [CompilerGenerated]
    private static Action<Character> <>f__am$cache8;
    [CompilerGenerated]
    private static Func<Asset, Level> <>f__am$cache9;
    [CompilerGenerated]
    private static Func<Instance, Vector3> <>f__am$cacheA;
    [SerializeField]
    private List<Instance> instances;
    public Func<Instance, bool> loadFilter;

    public static  event Action<Level> onAnyLoaded;

    static Level()
    {
        if (<>f__am$cache7 == null)
        {
            <>f__am$cache7 = new Action<Level>(Level.<onAnyLoaded>m__91);
        }
        onAnyLoaded = <>f__am$cache7;
        if (<>f__am$cache8 == null)
        {
            <>f__am$cache8 = new Action<Character>(Level.<Level>m__92);
        }
        Character.onAnyCreate = (Action<Character>) Delegate.Combine(Character.onAnyCreate, <>f__am$cache8);
    }

    [CompilerGenerated]
    private static void <Level>m__92(Character cha)
    {
        if (current != null)
        {
            cha.gameObject.AddComponent<DynamicObstacle>().pathfinder = current.pathfinder;
        }
    }

    [CompilerGenerated]
    private static void <onAnyLoaded>m__91(Level level)
    {
    }

    public Instance AddInstance(string prefabName, Vector3 position)
    {
        <AddInstance>c__AnonStorey59 storey = new <AddInstance>c__AnonStorey59 {
            position = position,
            prefabName = prefabName,
            <>f__this = this
        };
        if (string.IsNullOrEmpty(storey.prefabName))
        {
            return null;
        }
        Instance instance = this.instances.Find(new Predicate<Instance>(storey.<>m__94));
        if (instance != null)
        {
            this.RemoveInstance(instance.prefabName, storey.position);
        }
        Instance item = this.instances.Find(new Predicate<Instance>(storey.<>m__95));
        if (item == null)
        {
            item = new Instance(storey.prefabName, storey.position);
            item.Load(this.scene);
            this.instances.Add(item);
        }
        return item;
    }

    public Level Clone()
    {
        Level level = JsonUtility.FromJson<Level>(JsonUtility.ToJson(this));
        foreach (Instance instance in this.instances)
        {
            instance.guid = Guid.NewGuid().ToString();
        }
        return level;
    }

    private void GenerateAirWalls(Scene scene)
    {
        Vector3[] vectorArray = new Vector3[] { new Vector3(1f, 0f, 0f), new Vector3(-1f, 0f, 0f), new Vector3(0f, 0f, 1f), new Vector3(0f, 0f, -1f), new Vector3(1f, 0f, 1f), new Vector3(-1f, 0f, -1f), new Vector3(1f, 0f, -1f), new Vector3(-1f, 0f, 1f) };
        if (<>f__am$cacheA == null)
        {
            <>f__am$cacheA = x => x.position;
        }
        HashSet<Vector3> set = new HashSet<Vector3>(this.instances.Select<Instance, Vector3>(<>f__am$cacheA));
        HashSet<Vector3> set2 = new HashSet<Vector3>();
        foreach (Vector3 vector in set)
        {
            foreach (Vector3 vector2 in vectorArray)
            {
                Vector3 item = vector + vector2;
                if (!set.Contains(item))
                {
                    set2.Add(item);
                }
            }
        }
        foreach (Vector3 vector4 in set2)
        {
            BoxCollider collider = new GameObject("AirWall").AddComponent<BoxCollider>();
            collider.gameObject.layer = GameLayers.AirWall.index;
            collider.size = new Vector3(1f, 10f, 1f);
            collider.transform.position = vector4;
            SceneManager.MoveGameObjectToScene(collider.gameObject, scene);
        }
    }

    public static IEnumerable<Level> GetAllLevels()
    {
        if (<>f__am$cache9 == null)
        {
            <>f__am$cache9 = x => new Level { asset = x };
        }
        return AssetManager.GetAllLevelAssets().Select<Asset, Level>(<>f__am$cache9);
    }

    private string GetCategory(string name)
    {
        return Path.GetFileName(Path.GetDirectoryName(name));
    }

    public Instance GetInstance(int index)
    {
        return this.instances.GetElement<Instance>(index);
    }

    public List<Instance> GetInstances()
    {
        if (!this.isLoaded)
        {
            object[] args = new object[] { this.name };
            UnityEngine.Debug.LogErrorFormat("Could not get instances, '{0}' has not been loaded.", args);
            return null;
        }
        return this.instances;
    }

    public IEnumerable<Instance> GetInstances(Vector3 position)
    {
        <GetInstances>c__AnonStorey5B storeyb = new <GetInstances>c__AnonStorey5B {
            position = position
        };
        return this.instances.Where<Instance>(new Func<Instance, bool>(storeyb.<>m__97));
    }

    public static Level GetLevel(string levelName)
    {
        Asset asset = AssetManager.GetAsset(levelName);
        if (asset == null)
        {
            return null;
        }
        return new Level { asset = asset };
    }

    [DebuggerHidden]
    private static IEnumerable<Vector3> GetObstaclePoints(Collider co)
    {
        return new <GetObstaclePoints>c__Iterator9 { co = co, <$>co = co, $PC = -2 };
    }

    public Vector3 GetRandomWalkable()
    {
        return this.pathfinder.GetAllWalkable().GetRandomElement<Point3D>();
    }

    private void InitPathfinder()
    {
        this.pathfinder = new Pathfinder();
        Collider[] colliderArray = UnityEngine.Object.FindObjectsOfType<Collider>();
        foreach (Collider collider in colliderArray)
        {
            if (collider.gameObject.layer == GameLayers.Floor.index)
            {
                this.pathfinder.MarkWalkable(collider.transform.position.SetY(0f));
            }
        }
        LayerMask layerMask = (LayerMask) (GameLayers.Obstacle | GameLayers.Wall);
        foreach (Collider collider2 in colliderArray)
        {
            if (!collider2.isTrigger && layerMask.ContainsFlag(collider2.gameObject.layer))
            {
                this.pathfinder.MarkBlocked(collider2.transform.position.SetY(0f));
                IEnumerator<Vector3> enumerator = GetObstaclePoints(collider2).GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        Vector3 current = enumerator.Current;
                        this.pathfinder.MarkBlocked(current.SetY(0f));
                    }
                }
                finally
                {
                    if (enumerator == null)
                    {
                    }
                    enumerator.Dispose();
                }
            }
        }
    }

    private bool IsSameCatetory(string a, string b)
    {
        string category = this.GetCategory(a);
        string str2 = this.GetCategory(b);
        return ((category != "Misc") && (category == str2));
    }

    public Coroutine Load()
    {
        return this.Load(null);
    }

    public Coroutine Load(Action<float> progressCallback)
    {
        return Singleton<LevelHelper>.Instance.StartCoroutine(this.LoadRoutine(progressCallback));
    }

    [DebuggerHidden]
    private IEnumerator LoadRoutine(Action<float> progressCallback)
    {
        return new <LoadRoutine>c__Iterator8 { progressCallback = progressCallback, <$>progressCallback = progressCallback, <>f__this = this };
    }

    public void RegisterRuntimeInstance(GameObject instance)
    {
        if (!this.isLoaded)
        {
            object[] args = new object[] { this.name };
            UnityEngine.Debug.LogWarningFormat("Could not RegisterRuntimeInstance, level '{0}' has not been loaded.", args);
        }
        else
        {
            SceneManager.MoveGameObjectToScene(instance, this.scene);
        }
    }

    public void RemoveInstance(string prefabName, Vector3 position)
    {
        <RemoveInstance>c__AnonStorey5A storeya = new <RemoveInstance>c__AnonStorey5A {
            position = position,
            prefabName = prefabName
        };
        Instance item = this.instances.Find(new Predicate<Instance>(storeya.<>m__96));
        if (item != null)
        {
            item.Unload();
            this.instances.Remove(item);
        }
    }

    public void Save()
    {
        if (this.instances != null)
        {
            foreach (Instance instance in this.instances)
            {
                instance.OnBeforeSerialize();
            }
            string text = GameJsonUtility.ToJsonIgnoreDefaultValue(this);
            this.asset.SaveDataText(text);
        }
    }

    public static GameObject Spawn(GameObject prefab, Vector3 position)
    {
        GameObject instance = (GameObject) UnityEngine.Object.Instantiate(prefab, position, Quaternion.identity);
        instance.name = instance.name.Replace("(Clone)", string.Empty);
        if ((current != null) && current.isLoaded)
        {
            current.RegisterRuntimeInstance(instance);
        }
        return instance;
    }

    public void Unload()
    {
        if (!this.isLoaded)
        {
            object[] args = new object[] { this.name };
            UnityEngine.Debug.LogWarningFormat("Could not unload level '{0}', it has not been loaded.", args);
        }
        else
        {
            this.pathfinder = null;
            SceneManager.UnloadScene(this.scene);
            current = null;
        }
    }

    public Asset asset { get; set; }

    public static Level current
    {
        [CompilerGenerated]
        get
        {
            return <current>k__BackingField;
        }
        [CompilerGenerated]
        private set
        {
            <current>k__BackingField = value;
        }
    }

    public bool isLoaded
    {
        get
        {
            return (this.scene.isLoaded && (this.pathfinder != null));
        }
    }

    public string name
    {
        get
        {
            return this.asset.name;
        }
    }

    public Pathfinder pathfinder { get; private set; }

    public Scene scene { get; private set; }

    [CompilerGenerated]
    private sealed class <AddInstance>c__AnonStorey59
    {
        internal Level <>f__this;
        internal Vector3 position;
        internal string prefabName;

        internal bool <>m__94(Instance x)
        {
            return ((x.position == this.position) && this.<>f__this.IsSameCatetory(x.prefabName, this.prefabName));
        }

        internal bool <>m__95(Instance x)
        {
            return ((x.position == this.position) && (x.prefabName == this.prefabName));
        }
    }

    [CompilerGenerated]
    private sealed class <GetInstances>c__AnonStorey5B
    {
        internal Vector3 position;

        internal bool <>m__97(Instance x)
        {
            return (x.position == this.position);
        }
    }

    [CompilerGenerated]
    private sealed class <GetObstaclePoints>c__Iterator9 : IDisposable, IEnumerator, IEnumerable<Vector3>, IEnumerator<Vector3>, IEnumerable
    {
        internal Vector3 $current;
        internal int $PC;
        internal Collider <$>co;
        internal Bounds <bounds>__0;
        internal Vector3 <pos>__3;
        internal float <x>__1;
        internal float <z>__2;
        internal Collider co;

        [DebuggerHidden]
        public void Dispose()
        {
            this.$PC = -1;
        }

        public bool MoveNext()
        {
            uint num = (uint) this.$PC;
            this.$PC = -1;
            switch (num)
            {
                case 0:
                    this.<bounds>__0 = this.co.bounds;
                    this.<bounds>__0.Expand(new Vector3(0.1f, 100f, 0.1f));
                    this.$current = this.<bounds>__0.center;
                    this.$PC = 1;
                    goto Label_0184;

                case 1:
                    this.<x>__1 = this.<bounds>__0.min.x;
                    while (this.<x>__1 <= this.<bounds>__0.max.x)
                    {
                        this.<z>__2 = this.<bounds>__0.min.z;
                        while (this.<z>__2 <= this.<bounds>__0.max.z)
                        {
                            this.<x>__1 = Mathf.Round(this.<x>__1);
                            this.<z>__2 = Mathf.Round(this.<z>__2);
                            this.<pos>__3 = new Vector3(this.<x>__1, 0f, this.<z>__2);
                            if (this.<bounds>__0.Contains(this.<pos>__3))
                            {
                                this.$current = this.<pos>__3;
                                this.$PC = 2;
                                goto Label_0184;
                            }
                        Label_011A:
                            this.<z>__2++;
                        }
                        this.<x>__1++;
                    }
                    this.$PC = -1;
                    break;

                case 2:
                    goto Label_011A;
            }
            return false;
        Label_0184:
            return true;
        }

        [DebuggerHidden]
        public void Reset()
        {
            throw new NotSupportedException();
        }

        [DebuggerHidden]
        IEnumerator<Vector3> IEnumerable<Vector3>.GetEnumerator()
        {
            if (Interlocked.CompareExchange(ref this.$PC, 0, -2) == -2)
            {
                return this;
            }
            return new Level.<GetObstaclePoints>c__Iterator9 { co = this.<$>co };
        }

        [DebuggerHidden]
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.System.Collections.Generic.IEnumerable<UnityEngine.Vector3>.GetEnumerator();
        }

        Vector3 IEnumerator<Vector3>.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }

        object IEnumerator.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }
    }

    [CompilerGenerated]
    private sealed class <LoadRoutine>c__Iterator8 : IDisposable, IEnumerator, IEnumerator<object>
    {
        internal object $current;
        internal int $PC;
        internal Action<float> <$>progressCallback;
        internal Level <>f__this;
        internal string <dataText>__0;
        internal int <i>__1;
        internal Instance <ins>__2;
        internal float <loadingProgress>__3;
        internal Action<float> progressCallback;

        [DebuggerHidden]
        public void Dispose()
        {
            this.$PC = -1;
        }

        public bool MoveNext()
        {
            uint num = (uint) this.$PC;
            this.$PC = -1;
            switch (num)
            {
                case 0:
                {
                    Level.current = this.<>f__this;
                    if (!this.<>f__this.isLoaded)
                    {
                        this.<>f__this.pathfinder = null;
                        if (this.<>f__this.instances == null)
                        {
                            this.<dataText>__0 = this.<>f__this.asset.LoadDataText();
                            if (string.IsNullOrEmpty(this.<dataText>__0))
                            {
                                this.<dataText>__0 = "{}";
                            }
                            JsonUtility.FromJsonOverwrite(this.<dataText>__0, this.<>f__this);
                        }
                        this.<>f__this.scene = SceneManager.CreateScene(this.<>f__this.name);
                        this.<i>__1 = 0;
                        while (this.<i>__1 < this.<>f__this.instances.Count)
                        {
                            this.<ins>__2 = this.<>f__this.instances[this.<i>__1];
                            if ((this.<>f__this.loadFilter == null) || this.<>f__this.loadFilter(this.<ins>__2))
                            {
                                this.<ins>__2.index = this.<i>__1;
                                this.<ins>__2.Load(this.<>f__this.scene);
                                if (this.progressCallback != null)
                                {
                                    this.<loadingProgress>__3 = ((float) this.<i>__1) / ((float) this.<>f__this.instances.Count);
                                    if (((this.<i>__1 % 200) == 0) || (this.<i>__1 == (this.<>f__this.instances.Count - 1)))
                                    {
                                        this.progressCallback(this.<loadingProgress>__3);
                                        this.$current = null;
                                        this.$PC = 1;
                                        return true;
                                    }
                                }
                            }
                        Label_01D4:
                            this.<i>__1++;
                        }
                        this.<>f__this.GenerateAirWalls(this.<>f__this.scene);
                        this.<>f__this.InitPathfinder();
                        Level.onAnyLoaded(this.<>f__this);
                        this.$PC = -1;
                        break;
                    }
                    object[] args = new object[] { this.<>f__this.name };
                    UnityEngine.Debug.LogWarningFormat("Could not load level '{0}', it has been loaded.", args);
                    break;
                }
                case 1:
                    goto Label_01D4;
            }
            return false;
        }

        [DebuggerHidden]
        public void Reset()
        {
            throw new NotSupportedException();
        }

        object IEnumerator<object>.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }

        object IEnumerator.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }
    }

    [CompilerGenerated]
    private sealed class <RemoveInstance>c__AnonStorey5A
    {
        internal Vector3 position;
        internal string prefabName;

        internal bool <>m__96(Instance x)
        {
            return ((x.position == this.position) && (x.prefabName == this.prefabName));
        }
    }
}

